package com.kira.scaffoldmvc.Strategy;

import org.springframework.core.annotation.AnnotationAwareOrderComparator;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 多实例Bean容器，用于管理同一类型键对应多个策略Bean的场景
 * 继承自DefaultBeanContainer，泛型参数K为键类型，V为策略Bean类型且需实现IBeanType接口
 * 容器中存储的Value类型为List<V>，支持同一键对应多个策略Bean
 */
public abstract class MultipleBeanContainer<K, V extends IBeanType<K>> extends DefaultBeanContainer<K, List<V>> {

    /**
     * 创建Bean映射关系的核心方法（由父类DefaultBeanContainer调用）
     * 实现逻辑：
     * 1. 从Spring容器中获取所有指定类型的策略Bean
     * 2. 按beanType()方法的返回值对Bean进行分组
     * 3. 对每组Bean按@Order注解排序（或实现Ordered接口）
     * @return 键为K、值为List<V>的映射表
     */
    @Override
    protected Map<K, List<V>> createBeanMap() {
        // 获取Spring容器中所有类型为this.type的Bean实例（值类型为V）
        Collection<V> beanList = (Collection<V>) this.applicationContext.getBeansOfType(this.type).values();

        // 使用Stream API对Bean进行分组处理
        Map<K, List<V>> beanMap = beanList.stream()
                // 过滤掉beanType()返回null的无效Bean
                .filter(bean -> bean.beanType() != null)
                // 分组归约操作：
                // - 初始值：容量为8的HashMap
                // - 累加器：将每个Bean按beanType()分组到List中
                // - 组合器：并行流时合并两个Map（此处简单返回a）
                .reduce(new HashMap<>(8), (beansMap, bean) -> {
                    // 获取当前Bean对应的键（通过IBeanType接口的beanType()方法）
                    K beanType = bean.beanType();
                    // 从Map中获取该键对应的Bean列表，不存在则创建新ArrayList
                    List<V> existedBeanList = beansMap.getOrDefault(beanType, new ArrayList<>());
                    // 将当前Bean添加到列表中
                    existedBeanList.add(bean);
                    // 更新Map中的列表
                    beansMap.put(beanType, existedBeanList);
                    return beansMap;
                }, (a, b) -> a); // 并行流时的合并逻辑（此处无实际作用）

        // 对每个键对应的Bean列表按@Order注解或Ordered接口排序
        for (List<V> beans : beanMap.values()) {
            AnnotationAwareOrderComparator.sort(beans);
        }

        return beanMap;
    }
}